package com.eleventwelve.iris.entity;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Years;
import org.opentides.bean.Auditable;
import org.opentides.bean.AuditableField;
import org.opentides.bean.BaseEntity;
import org.opentides.bean.FileInfo;
import org.opentides.bean.Searchable;
import org.opentides.bean.Sortable;
import org.opentides.bean.SystemCodes;
import org.opentides.bean.Uploadable;
import org.springframework.web.multipart.MultipartFile;

import com.eleventwelve.iris.utilities.ScannedFileContainer;

/**
 * 
 * @author Ashley
 *
 */
@Entity
@Table(name="PATIENT")
public class Patient extends BaseEntity implements Sortable, Auditable, Searchable, PhotoUploadable, Uploadable, ScannedFileContainer {
	private static final long serialVersionUID = -7255120575800642238L;

	@Column(name="FIRST_NAME")
	private String firstName;
	
	@Column(name="MIDDLE_NAME")
	private String middleName;
	
	@Column(name="LAST_NAME")
	private String lastName;
	
	@Column(name="NICKNAME")
	private String nickname;
	
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="GENDER")
	private SystemCodes gender;
	
	@Temporal(TemporalType.DATE)
	@Column(name="BIRTHDATE")
	private Date birthdate;
	
	@Lob
	@Column(name="ADDRESS")
	private String address;
	
	@Column(name="EMAIL_ADDRESS")
	private String emailAddress;
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "owner", cascade = { CascadeType.ALL })
	private List<ContactNumber> contactNumbers;
	
	@Temporal(TemporalType.DATE)
	@Column(name="REGISTRATION_DATE")
	private Date registrationDate;
	
	@Lob
	@Column(name="NOTES")
	private String notes;
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "patient")
	private List<Treatment> treatments;
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "patient")
	private List<PatientMedicalProgram> patientMedicalPrograms;
	
	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "patient")
	private List<PatientAllergy> patientAllergies;
	
	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "patient")
	private List<PatientDisease> patientDiseases;
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinTable(name = "PATIENT_FILES", joinColumns = { @JoinColumn(name = "PATIENT_ID", referencedColumnName = "ID") }, inverseJoinColumns = @JoinColumn(name = "FILE_INFO_ID"))
	private List<FileInfo> files;
	
	
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinTable(name = "PATIENT_SCANNED_FILES", joinColumns = { @JoinColumn(name = "PATIENT_ID", referencedColumnName = "ID") }, inverseJoinColumns = @JoinColumn(name = "FILE_INFO_ID"))
	private List<FileInfo> scannedFiles;
	
	@Transient
	private transient MultipartFile tempFile;
	
	
	
	
	
	@Transient
	private MultipartFile photo;
	
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getMiddleName() {
		return middleName;
	}

	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public SystemCodes getGender() {
		return gender;
	}

	public void setGender(SystemCodes gender) {
		this.gender = gender;
	}

	public Date getBirthdate() {
		return birthdate;
	}

	public void setBirthdate(Date birthdate) {
		this.birthdate = birthdate;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getEmailAddress() {
		return emailAddress;
	}

	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}

	public Date getRegistrationDate() {
		return registrationDate;
	}

	public void setRegistrationDate(Date registrationDate) {
		this.registrationDate = registrationDate;
	}

	public List<ContactNumber> getContactNumbers() {
		return contactNumbers;
	}
	

	public void setContactNumbers(List<ContactNumber> contactNumbers) {
		this.contactNumbers = contactNumbers;
	}

	public String getNotes() {
		return notes;
	}

	public void setNotes(String notes) {
		this.notes = notes;
	}
	
	public List<PatientAllergy> getPatientAllergies() {
		return patientAllergies;
	}

	public void setPatientAllergies(List<PatientAllergy> patientAllergies) {
		this.patientAllergies = patientAllergies;
	}

	public List<PatientDisease> getPatientDiseases() {
		return patientDiseases;
	}

	public void setPatientDiseases(List<PatientDisease> patientDiseases) {
		this.patientDiseases = patientDiseases;
	}

	@Override
	public AuditableField getPrimaryField() {
		return new AuditableField("lastName");
	}

	public String getNickname() {
		return nickname;
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	
	public int getAge(){
		DateMidnight birthdate = new DateMidnight(this.birthdate);
		DateTime now = new DateTime();
		Years age = Years.yearsBetween(birthdate, now);
		return age.getYears();
	}
	
	public String getFullName(){
		String fullname = "";
		fullname += this.firstName+" ";
		if (!StringUtils.isEmpty(this.middleName)) {
			fullname += this.middleName.charAt(0)+". ";
		}
		fullname += this.lastName;
		return fullname;
	}
	
	public List<ContactNumber> getMobileNumbers(){
		List<ContactNumber> mobileNumbers = new ArrayList<ContactNumber>();
		if(this.getContactNumbers()!=null){
			for (ContactNumber contactNumber : this.contactNumbers) {
				if(contactNumber.getType().getValue().equals("Mobile")){
					mobileNumbers.add(contactNumber);
				}
			}
		}
		
		return mobileNumbers;
	}
	
	public List<ContactNumber> getLandlineNumbers(){
		List<ContactNumber> landlineNumbers = new ArrayList<ContactNumber>();
		if(this.getContactNumbers()!=null){
			for (ContactNumber contactNumber : this.contactNumbers) {
				if(contactNumber.getType().getValue().equals("Landline")){
					landlineNumbers.add(contactNumber);
				}
			}
		}
		
		return landlineNumbers;
	}
	
	public List<PatientAllergy> getActiveAllergies(){
		List<PatientAllergy> activeAllergies = new ArrayList<PatientAllergy>();
		if(this.patientAllergies!=null){
			for (PatientAllergy patientAllergy : this.patientAllergies) {
				if(!patientAllergy.getIsDeleted() && patientAllergy.getAllergyStatus().getValue().equals("Active")){
					activeAllergies.add(patientAllergy);
				}
			}
		}
		
		
		return activeAllergies;
	}
	
	public List<PatientAllergy> getInactiveAllergies(){
		List<PatientAllergy> inactiveAllergies = new ArrayList<PatientAllergy>();
		if(this.patientAllergies!=null){
			for (PatientAllergy patientAllergy : this.patientAllergies) {
				if(!patientAllergy.getIsDeleted() && patientAllergy.getAllergyStatus().getValue().equals("Inactive")){
					inactiveAllergies.add(patientAllergy);
				}
			}
		}
		return inactiveAllergies;
	}
	
	public List<PatientDisease> getPastDiseases(){
		List<PatientDisease> diseases = new ArrayList<PatientDisease>();
		if(this.patientDiseases!=null){
			for (PatientDisease patientDisease : this.patientDiseases) {
				if(!patientDisease.getIsDeleted() && patientDisease.getDiseaseStatus().getValue().equals("Past")){
					diseases.add(patientDisease);
				}
			}
		}
		
		
		return diseases;
	}
	
	public List<PatientDisease> getPresentDiseases(){
		List<PatientDisease> diseases = new ArrayList<PatientDisease>();
		if(this.patientDiseases!=null){
			for (PatientDisease patientDisease : this.patientDiseases) {
				if(!patientDisease.getIsDeleted() && patientDisease.getDiseaseStatus().getValue().equals("Present")){
					diseases.add(patientDisease);
				}
			}
		}
		
		return diseases;
	}
	
	@Override
	public List<String> getSearchProperties() {
		List<String> searchProperties = new ArrayList<String>();
		searchProperties.add("lastName");
		searchProperties.add("firstName");
		searchProperties.add("nickname");
		return searchProperties;
	}
	
	public List<PatientMedicalProgram> getSortedPrograms(){
		if(patientMedicalPrograms!=null && patientMedicalPrograms.size()>0){
			List<PatientMedicalProgram> sortedPrograms = new ArrayList<PatientMedicalProgram>();
			sortedPrograms.addAll(patientMedicalPrograms);
			Collections.sort(sortedPrograms, new Comparator<PatientMedicalProgram>() {
			    public int compare(PatientMedicalProgram p1, PatientMedicalProgram p2) {
			    	if(p1.getCreateDate()!=null || p2.getCreateDate()!=null){
			    		return p2.getCreateDate().compareTo(p1.getCreateDate());
			    	}
			    	return 0;
			    }
			});
			
			return sortedPrograms;
		}
		return null;
	}
	
	public List<Treatment> getSortedTreatment(){
		if(treatments!=null && treatments.size()>0){
			List<Treatment> sortedTreatments = new ArrayList<Treatment>();
			sortedTreatments.addAll(treatments);
			Collections.sort(sortedTreatments, new Comparator<Treatment>() {
			    public int compare(Treatment t1, Treatment t2) {
			    	if(t1.getTreatmentDate()!=null || t2.getTreatmentDate()!=null){
			    		return t2.getTreatmentDate().compareTo(t1.getTreatmentDate());
			    	}
			    	return 0;
			    }
			});
			
			return sortedTreatments;
		}
		return null;
	}

	public List<Treatment> getTreatments() {
		return treatments;
	}

	public void setTreatments(List<Treatment> treatments) {
		this.treatments = treatments;
	}

	public List<PatientMedicalProgram> getPatientMedicalPrograms() {
		return patientMedicalPrograms;
	}

	public void setPatientMedicalPrograms(List<PatientMedicalProgram> patientMedicalPrograms) {
		this.patientMedicalPrograms = patientMedicalPrograms;
	}

	@Override
	public List<FileInfo> getFiles() {
		return files;
	}

	@Override
	public void setFiles(List<FileInfo> files) {
		this.files = files;
	}

	@Override
	public MultipartFile getPhoto() {
		return photo;
	}

	public void setPhoto(MultipartFile photo) {
		this.photo = photo;
	}

	public MultipartFile getTempFile() {
		return tempFile;
	}

	public void setTempFile(MultipartFile tempFile) {
		this.tempFile = tempFile;
	}

	@Override
	public List<FileInfo> getScannedFiles() {
		return this.scannedFiles;
	}
	
	public List<FileInfo> getOrderedScannedFiles() {
		List<FileInfo> ordered = new ArrayList<FileInfo>(this.scannedFiles);
		Collections.reverse(ordered);
		return ordered;
	}

	@Override
	public void setScannedFiles(List<FileInfo> paramList) {
		this.scannedFiles = paramList;
	}
}
